//*************************************************************************************************
// OLEMACH.CPP
//
// This file contains a bunch of miscellaneous OLE overhead stuff.  It includes GetClassObject,
// self registration code and all of the class factories.
//*************************************************************************************************
#include "stdafx.h"							// Precompiled header key.
#include "olehelp.h"						// OLE helper routines.
#include "ssautoi.h"						// Internal SourceSafe automation defs.

// Global variables for the COM server DLL.
LONG			giObj = 0;					// # of OLE objects running in DLL
LONG			giLock = 0;					// Count of locks on DLL.

// See dllmain.cpp for DllRegisterServer

//*************************************************************************************************
// Create a class factory object for the specified class (rclsid) and fill ppvObj with an interface
// pointer to requested interface on the class factory.
//*************************************************************************************************
STDAPI DllGetClassObject(					// HRESULT return status.
	REFCLSID	rclsid,						// Class ID that we want to create.
	REFIID		riid,						// Interface ID that we want.
	PVOID		*ppvObj)					// Buffer for the interface pointer.
{
	LPWSTR   pwszShellExt, pwszShellExt2;
	StringFromIID(rclsid, &pwszShellExt);    
	StringFromIID(riid, &pwszShellExt2);    
	Trace::Write("Enter DllGetClassObject CLSID = %ls, REFIID = %ls", pwszShellExt, pwszShellExt2);

	IClassFactory *pObj;					// Internal class factory object.
	HRESULT		hr;							// Return status.

	// Check if the caller is asking for one of the classes we support and
	// create the class factory object for it.
	if (rclsid == CLSID_VSSDatabase)
	{
		pObj = (IClassFactory *)(new CVSSDatabaseClsFac());
	}
	else
	{
		return CLASS_E_CLASSNOTAVAILABLE;
	}

	// Check if the class factory was created.
	if (pObj == NULL)
	{
		return E_OUTOFMEMORY;
	}

	// Retrieve the requested interface and return.
	if (FAILED(hr = pObj->QueryInterface(riid, ppvObj)))
	{
		delete pObj;
	}
	return hr;
}

//*************************************************************************************************
// Check if there are any active objects in this DLL or if the DLL is locked and return whether the
// DLL can be unloaded or not.
//*************************************************************************************************
STDAPI DllCanUnloadNow()					// S_OK - ok to unload, S_FALSE - no.
{
	Trace::Write("Enter DllCanUnloadNow");
	return (giObj == 0 && giLock == 0) ? S_OK : S_FALSE;
}


//*************************************************************************************************
// Constructor for the class factory object.
//*************************************************************************************************
CVSSDatabaseClsFac::CVSSDatabaseClsFac() :
	m_cRef(0)
{
	Trace::Write("Enter CVSSDatabaseClsFac::CVSSDatabaseClsFac");
	++giObj;
}

//*************************************************************************************************
// Destructor for the class factory object.
//*************************************************************************************************
CVSSDatabaseClsFac::~CVSSDatabaseClsFac()
{
	Trace::Write("Enter CVSSDatabaseClsFac::~CVSSDatabaseClsFac");
	--giObj;
}

//*************************************************************************************************
// The query interface implementation for the class factory.
//*************************************************************************************************
HRESULT CVSSDatabaseClsFac::QueryInterface(	// Did we get an interface?
	REFIID		riid,						// ID of the interface we want.
	LPVOID		*ppvObj)					// Buffer for the interface pointer.
{
	Trace::Write("Enter CVSSDatabaseClsFac::QueryInterface");

	// Init the returned pointer to NULL.
	*ppvObj = NULL;

	// If it is one of the interfaces we support, set the interface pointer.
	if (riid == IID_IUnknown ||
		riid == IID_IClassFactory)
	{
		*ppvObj = this;
	}
	else
	{
		LPWSTR   pwszShellExt;
		StringFromIID(riid, &pwszShellExt);    
		Trace::Write("E_NOINTERFACE IID = %ls", pwszShellExt);
		return E_NOINTERFACE;
	}

	// AddRef the interface pointer we are returning.
	((LPUNKNOWN)*ppvObj)->AddRef();
	return S_OK;
}

//*************************************************************************************************
// AddRef on the interface increments the interface's reference count.
//*************************************************************************************************
ULONG CVSSDatabaseClsFac::AddRef()
{
	Trace::Write("Enter CVSSDatabaseClsFac::AddRef");

	return ++m_cRef;
}

//*************************************************************************************************
// Release on the interface decrements the interface's reference count, deleting the object if the
// count hits 0.
//*************************************************************************************************
ULONG CVSSDatabaseClsFac::Release()
{
	Trace::Write("Enter CVSSDatabaseClsFac::Release");

	ULONG		cRef;						// Temp count because "this" is deleted.

	// Decrement the reference count and delete the object if it hits 0.
	if ((cRef = --m_cRef) == 0)
	{
		delete this;
	}
	return cRef;
}

//*************************************************************************************************
// Create an instance of the object class that this class factory is written to create.  Return in
// ppvObj the interface pointer specified by riid (if that interface is supported).
//*************************************************************************************************
HRESULT CVSSDatabaseClsFac::CreateInstance( // Object created?
	LPUNKNOWN	pUnkOuter,					// Outer unknown this object should use.
	REFIID		riid,						// ID of interface caller wants.
	LPVOID		*ppvObj)					// Buffer for the interface pointer.
{
	Trace::Write("Enter CVSSDatabaseClsFac::CreateInstance");

	HRESULT		hr;							// Returned result.
	CVSSDatabase *pObj;						// Pointer to created object.

	// Init the returned interface pointer and the result code.
	*ppvObj = NULL;
	hr = E_OUTOFMEMORY;

	// If the caller passes us an outer unknown, they must ask for out IUnknown.
	if (pUnkOuter != NULL /* && riid != IID_IUnknown */)
	{
		return CLASS_E_NOAGGREGATION;
	}

	// Create the repository.
	if ((pObj = new CVSSDatabase()) == NULL)
	{
		return hr;
	}

	// Get the interface the caller requested.
	if (FAILED(hr = pObj->QueryInterface(riid, ppvObj)))
	{
		delete pObj;
	}
	return hr;
}

//*************************************************************************************************
// This allows clients to lock this server (dll) in memory (or unlock it).
//*************************************************************************************************
HRESULT CVSSDatabaseClsFac::LockServer(
	BOOL		bLock)						// TRUE = lock, FALSE = unlock.
{
	Trace::Write("Enter CVSSDatabaseClsFac::LockServer");

	// The lock count is simply kept in a global variable.
	if (bLock)
	{
		++giLock;
	}
	else
	{
		--giLock;
	}
	return NOERROR;
}
